/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       popup_window.cpp

	$Header: /game/popup_window.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "popup_window.h"

#include "mouse_event.h"

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
t_popup_window::t_popup_window(  t_transparency transparency, t_window* parent  )
              : t_window( transparency, parent )
{
	m_passing_event = false;
	capture_mouse();
}


// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
t_popup_window::t_popup_window( t_screen_point point, t_window* parent )
              : t_window( t_screen_rect( point.x, point.y, point.x, point.y ), 
			              k_completely_transparent, parent )
{
	m_passing_event = false;
	capture_mouse();
}


// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
t_popup_window::t_popup_window( t_screen_rect const& rect, t_window* parent )
              : t_window( rect, k_completely_transparent, parent )
{
	m_passing_event = false;
	capture_mouse();
}


// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void t_popup_window::on_close()
{
	release_mouse();
	m_last_mouse_window = 0;
}


// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
bool t_popup_window::children_handle_mouse()
{
	return false;
}


// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void t_popup_window::pass_event( t_mouse_function function, t_mouse_event const& event,
								 bool check_close, bool forward_after_close )
{
	// we have the mouse captured, so re-send all messages we get to the appropriate window.
	if (m_passing_event)
		return;

	// try to pass events to children, first.
	t_window_ptr window = get_child( event.client_point );
	
	// if that fails, allow them to pass to the modal window.
	if (window == 0)
	{
		window = get_modal_window();
		
		t_screen_point point = window->to_client( event.screen_point );

		window = window->get_child( point );
	}

	// Close the popup if another window got clicked
	// REVISED:  Now close on _any_ mouse click (so we close if the get clicked ourselves)
	// unless the derived class tells us its children will handle mouse events.
	if (check_close) 
	{
		if (!children_handle_mouse() || (window.get() == this || !is_child( window )))
		{
			close();
			window = get_mouse_window( event.screen_point );
		}
	}

	// Forward the mouse button event if we were told to
	if (window != 0 && (children_handle_mouse() || forward_after_close))
	{
		t_mouse_event new_event = event;

		m_passing_event = true;
		new_event.client_point = window->to_client( event.screen_point );
		( window->*function )( new_event );
		m_passing_event = false;
	}
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// we have the mouse captured, so re-send all messages we get to the appropriate window.
// ---------------------------------------------------------------------------
void t_popup_window::left_button_down( t_mouse_event const& event )
{
	pass_event( &t_window::left_button_down, event, false, false );
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// we have the mouse captured, so re-send all messages we get to the appropriate window.
// ---------------------------------------------------------------------------
void t_popup_window::left_button_up( t_mouse_event const& event )
{
	pass_event( &t_window::left_button_up, event, true, false );
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// we have the mouse captured, so re-send all messages we get to the appropriate window.
// ---------------------------------------------------------------------------
void t_popup_window::left_double_click( t_mouse_event const& event )
{
	pass_event( &t_window::left_double_click, event, true, false );
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void t_popup_window::mouse_move( t_mouse_event const& event )
{
	// we have the mouse captured, so re-send all messages we get to the appropriate window.
	if (m_passing_event)
		return;

	m_passing_event = true;

	// try to pass events to children, first.
	t_window_ptr window = get_child( event.client_point );
	
	// if that fails, allow them to pass to the modal window.
	if (window == 0)
	{
		window = get_modal_window();
		
		t_screen_point point = window->to_client( event.screen_point );

		window = window->get_child( point );
	}

	if (window != m_last_mouse_window && m_last_mouse_window != 0)
	{
		t_mouse_event mouse_event = event;

		mouse_event.client_point = m_last_mouse_window->to_client( event.screen_point );
		m_last_mouse_window->mouse_leaving( m_last_mouse_window, 
			                                window, mouse_event );
	}

	m_last_mouse_window = window;
	if (window != 0)
	{
		t_mouse_event new_event = event;

		new_event.client_point = window->to_client( event.screen_point );
		window->mouse_move( event );
	}
	m_passing_event = false;
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void t_popup_window::right_button_down( t_mouse_event const& event )
{
	pass_event( &t_window::right_button_down, event, true, true );
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void t_popup_window::right_button_up( t_mouse_event const& event )
{
	pass_event( &t_window::right_button_up, event, false, true );
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void t_popup_window::right_double_click( t_mouse_event const& event )
{
	pass_event( &t_window::right_double_click, event, true, true );
}

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void  t_popup_window::add_child( t_window* window )
{
	t_window::add_child( window );

	t_screen_rect rect = get_screen_rect();

	if (rect.height() == 0)
		rect = window->get_screen_rect();
	else
		rect = get_extent( rect, window->get_screen_rect() );

	// change window's size.
	move_screen_rect( rect, false );
} // add a child window

// ---------------------------------------------------------------------------
// window which closes if any click occurs outside the window
// ---------------------------------------------------------------------------
void t_popup_window::update_size()
{
	t_window_list::iterator index = get_children_begin();
	t_screen_rect           rect(0,0,0,0);

	// exit if there are no children.
	if (index == get_children_end())
		return;

	// find the total screen rectangle occupied by all children
	rect = (*index)->get_screen_rect();
	index++;
	while (index != get_children_end())
	{
		rect = get_extent( (*index)->get_screen_rect(), rect );
		index++;
	}
	move_screen_rect( rect, false );
}
